`ifndef __HAMMING_DECODER__
`define __HAMMING_DECODER__

module hamming_decoder (
           input clk,
           input clk2,
           input rst_n,
           input din,
           input din_valid,
           output dout,
           output dout_valid,
           output error);

reg dout_reg;
reg dout_valid_reg;
reg error_reg;
reg output_enable;
reg [2: 0] input_cnt;
reg [6: 0] input_buffer_in;
reg [7: 0] input_buffer;
reg [1: 0] output_rest;
reg [3: 0] output_buffer;

`define P1 (input_buffer[0])
`define P2 (input_buffer[1])
`define P3 (input_buffer[3])
`define D1 (input_buffer[2])
`define D2 (input_buffer[4])
`define D3 (input_buffer[5])
`define D4 (input_buffer[6])

`define C1 (`D1 ^ `D2 ^ `D4 ^ `P1)
`define C2 (`D1 ^ `D3 ^ `D4 ^ `P2)
`define C3 (`D2 ^ `D3 ^ `D4 ^ `P3)
`define Pa ^(input_buffer[7:0])

assign dout_valid = dout_valid_reg;
assign dout = (dout_valid_reg == 1) ? dout_reg : 1'bX;
assign error = error_reg;

always @(posedge clk2 or negedge rst_n) begin
    if (rst_n == 0) begin
        input_cnt <= 0;
        input_buffer <= 0;
        input_buffer_in <= 0;
        output_rest <= 0;
        output_buffer <= 0;
        dout_reg <= 0;
        dout_valid_reg <= 0;
        output_enable <= 0;
        error_reg <= 0;
    end
    else begin
        if (clk == 1) begin
            if (output_rest == 0) begin
                if (output_enable == 1) begin
                    output_rest <= 3;
                    if ((`C1 | `C2 | `C3 != 0) && (`Pa == 0)) begin // 检测传输出现两位错误
                        dout_valid_reg <= 0; // 否决输出，传输错误
                        error_reg <= 1;
                    end
                    else begin
                        error_reg <= 0;
                        dout_valid_reg <= 1;
                        if ((!`C3) & `C2 & `C1) begin
                            output_buffer <= {`D4, `D3, `D2, ~`D1};
                            dout_reg <= `D4;
                        end
                        else if ((!`C2) & `C3 & `C1) begin
                            output_buffer <= {`D4, `D3, ~`D2, `D1};
                            dout_reg <= `D4;
                        end
                        else if ((!`C1) & `C3 & `C2) begin
                            output_buffer <= {`D4, ~`D3, `D2, `D1};
                            dout_reg <= `D4;
                        end
                        else if (`C1 & `C3 & `C2)begin
                            output_buffer <= {~`D4, `D3, `D2, `D1};
                            dout_reg <= ~`D4;
                        end
                        else begin // 没有发生任何错误
                            output_buffer <= {`D4, `D3, `D2, `D1};
                            dout_reg <= `D4;
                        end
                    end
                end
                else begin
                    dout_valid_reg <= 0;
                    dout_reg <= 0;
                end
            end
            else begin
                dout_reg <= output_buffer[output_rest - 1];
                output_rest <= output_rest - 1'b1;
            end
        end
        else ;

        if (din_valid == 1) begin
            if (input_cnt == 7) begin
                input_cnt <= 0;
                output_enable <= 1;
                input_buffer <= {din, input_buffer_in[6:0]};
            end
            else begin
                input_buffer_in[input_cnt] <= din;
                input_cnt <= input_cnt + 1'b1;
            end
        end
        else begin
            if (clk)
                output_enable <= 0;
            else ;
        end

    end
end

endmodule

`endif